package com.bacon.gmall.list.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bacon.gmall.list.dao.GoodsDao;
import com.bacon.gmall.list.service.ListService;
import com.bacon.gmall.model.list.*;
import com.bacon.gmall.model.product.BaseCategoryView;
import com.bacon.gmall.model.product.BaseTrademark;
import com.bacon.gmall.model.product.SkuAttrValue;
import com.bacon.gmall.model.product.SkuInfo;
import com.bacon.gmall.product.client.ProductFeignClient;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author： bacon、
 * @version： 1.0
 * @create： 2020-12-28 19:42
 * @description:
 */
@Service
public class ListServiceImpl implements ListService {


    @Autowired
    private GoodsDao goodsDao;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    //商品上架
    @Override
    public void onSale(Long skuId) {
        Goods goods = new Goods();

        //获取skuinfo信息
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
        goods.setDefaultImg(skuInfo.getSkuDefaultImg()); //默认图片
        goods.setPrice(skuInfo.getPrice().doubleValue()); //价格
        goods.setTitle(skuInfo.getSkuName()); //标题
        goods.setCreateTime(new Date());
        goods.setId(skuId);

        //获取品牌信息
        BaseTrademark baseTrademark = productFeignClient.getBaseTrademark(skuInfo.getTmId());
        goods.setTmId(baseTrademark.getId());
        goods.setTmName(baseTrademark.getTmName());
        goods.setTmLogoUrl(baseTrademark.getLogoUrl());

        //获取三级分类
        BaseCategoryView baseCategoryView = productFeignClient.getBaseCategoryView(skuInfo.getCategory3Id());
        goods.setCategory3Id(baseCategoryView.getCategory3Id());
        goods.setCategory3Name(baseCategoryView.getCategory3Name());
        goods.setCategory2Id(baseCategoryView.getCategory2Id());
        goods.setCategory2Name(baseCategoryView.getCategory2Name());
        goods.setCategory1Id(baseCategoryView.getCategory1Id());
        goods.setCategory1Name(baseCategoryView.getCategory1Name());

        //查询平台属性表
        List<SkuAttrValue> baseAttrInfoAndBaseAttrValue =
                productFeignClient.getBaseAttrInfoAndBaseAttrValue(skuId);
        List<SearchAttr> searchAttrList = baseAttrInfoAndBaseAttrValue.stream().map((skuAttrValue) -> {

            SearchAttr searchAttr = new SearchAttr();

            //平台属性ID
            searchAttr.setAttrId(skuAttrValue.getBaseAttrInfo().getId());

            //平台属性名称
            searchAttr.setAttrName(skuAttrValue.getBaseAttrInfo().getAttrName());

            //平台属性值名称
            searchAttr.setAttrValue(skuAttrValue.getBaseAttrValue().getValueName());
            return searchAttr;
        }).collect(Collectors.toList());
        goods.setAttrs(searchAttrList);
        goodsDao.save(goods);
    }

    @Override
    public void hotScore(Long skuId) {
        String redisName = "hotScore";
        Double score = redisTemplate.opsForZSet().incrementScore(redisName, skuId, 1);
        if (score % 10 == 0) {
            Optional<Goods> optionalGoods = goodsDao.findById(skuId);
            Goods goods = optionalGoods.get();
            goods.setHotScore(score.longValue());


            goodsDao.save(goods);

        }
    }

    //开始搜索 ， 带着所有条件
    @Override
    public SearchResponseVo list(SearchParam searchParam) {
        //1、建立索引库连接
        SearchRequest searchRequest = buliderSearchRequest(searchParam);

        //2、执行搜索
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.
                    search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //3、解析结果
        SearchResponseVo responseVo = parseSearchResponse(searchResponse);
        responseVo.setPageNo(searchParam.getPageNo());
        responseVo.setPageSize(searchParam.getPageSize());
        responseVo.setTotalPages((long) (responseVo.getTotal() - 1 + searchParam.getPageSize() / searchParam.getPageSize()));
        return responseVo;
    }


    private SearchRequest buliderSearchRequest(SearchParam searchParam) {

        //创建请求连接 ，   执行搜索的时候  请求对象
        //负责：负责所有 ， 索引库名字
        SearchRequest searchRequest = new SearchRequest();

        //创建条件装载对象
        //负责：排序、分页、聚合
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置条件,多条件
        //负责：关键词及过滤条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //设置title条件
        String keyword = searchParam.getKeyword();
        if (!StringUtils.isEmpty(keyword)) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("title", keyword).operator(Operator.AND));
        } else {
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }

        //设置品牌信息
        String trademarkUnchanged = searchParam.getTrademark();
        if (!StringUtils.isEmpty(trademarkUnchanged)) {
            String[] trademark = trademarkUnchanged.split(":");
            boolQueryBuilder.filter(QueryBuilders.termQuery("tmId", trademark[0]));
        }

        //分类Id
        Long category1Id = searchParam.getCategory1Id();
        if (null != category1Id) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("category1Id", category1Id));
        }
        Long category2Id = searchParam.getCategory2Id();
        if (null != category2Id) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("category2Id", category2Id));
        }
        Long category3Id = searchParam.getCategory3Id();
        if (null != category3Id) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("category3Id", category3Id));
        }

        String[] props = searchParam.getProps();
        if (null != props && props.length > 0) {

            //相当于[]
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            for (String prop : props) {

                //子对象相当于 {}
                BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();
                //平台属性为----->  平台属性Id ： 平台属性值名称 ： 平台属性名称
                String[] s = prop.split(":");

                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrId", s[0]));
                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrValue", s[1]));

                //嵌套关系
                boolQuery.must(QueryBuilders.nestedQuery("attrs", subBoolQuery, ScoreMode.None));
            }
            //嵌套关系
            boolQueryBuilder.filter(boolQuery);

        }


        //排序
        String order = searchParam.getOrder();

        if (!StringUtils.isEmpty(order)) {
            String[] split = order.split(":");
            if (null != split && split.length == 2) {
                String s = "";
                switch (split[0]) {
                    case "1":
                        s = "hotScore";
                        break;
                    case "2":
                        s = "price";
                        break;
                }
                searchSourceBuilder.sort(s,
                        split[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC);
            }

        } else {
            searchSourceBuilder.sort("hotScore", SortOrder.DESC);
        }

        //每页起始数据
        searchSourceBuilder.from((searchParam.getPageNo() - 1) * searchParam.getPageSize());

        //每页多少数据
        searchSourceBuilder.size(searchParam.getPageSize());

        //输入关键字高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //根据关键词查品牌集合
        // 华为 小米  苹果    group by  ==  ES 索引库 聚合 select max(id) as idddd from
        // 品牌ID 品牌名称 品牌Logo
        searchSourceBuilder.aggregation(
                AggregationBuilders.terms("tmIdAgg").field("tmId").
                        subAggregation(AggregationBuilders.terms("tmNameAgg").field("tmName")).
                        subAggregation(AggregationBuilders.terms("tmLogoUrlAgg").field("tmLogoUrl")));


        searchSourceBuilder.aggregation(
                AggregationBuilders.nested("attrsAgg", "attrs").
                        subAggregation(AggregationBuilders.terms("attrIdAgg").field("attrs.attrId").
                                subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName")).
                                subAggregation(AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue"))));

        searchSourceBuilder.query(boolQueryBuilder);
        System.out.println(searchSourceBuilder.toString());//DSL
        searchRequest.source(searchSourceBuilder);
        searchRequest.indices("goods");
        return searchRequest;
    }

    //结果解析
    private SearchResponseVo parseSearchResponse(SearchResponse searchResponse) {

        SearchResponseVo vo = new SearchResponseVo();

        //1、总条数
        SearchHits hits = searchResponse.getHits();
        System.out.println("总数量为 -----> " + hits.getTotalHits());
        vo.setTotal(hits.getTotalHits());

        //2、商品数量
        SearchHit[] hits1 = hits.getHits();
        List<Goods> goodsList = Arrays.stream(hits1).map((hit) -> {
            String sourceAsString = hit.getSourceAsString();

            //将高亮标题替换原标题
            Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (null != highlightFields) {
                HighlightField title = highlightFields.get("title");
                if (null != title) {
                    String s = title.fragments()[0].toString();
                    goods.setTitle(s);
                }
            }
            return goods;

        }).collect(Collectors.toList());

        vo.setGoodsList(goodsList);

        //聚合后的数据
        Aggregations aggregations = searchResponse.getAggregations();
        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();

        //解析品牌集合
        ParsedLongTerms tmIdAgg = (ParsedLongTerms) stringAggregationMap.get("tmIdAgg");
        List<SearchResponseTmVo> tmVos = tmIdAgg.getBuckets().stream().map((bucket) -> {
            SearchResponseTmVo searchResponseTmVo = new SearchResponseTmVo();
            searchResponseTmVo.setTmId(Long.valueOf(bucket.getKeyAsString()));

            ParsedStringTerms tmNameAgg = bucket.getAggregations().get("tmNameAgg");
            searchResponseTmVo.setTmName(tmNameAgg.getBuckets().get(0).getKeyAsString());

            ParsedStringTerms tmLogoUrlAgg = bucket.getAggregations().get("tmLogoUrlAgg");
            searchResponseTmVo.setTmLogoUrl(tmLogoUrlAgg.getBuckets().get(0).getKeyAsString());
            return searchResponseTmVo;
        }).collect(Collectors.toList());
        vo.setTrademarkList(tmVos);

        //解析商品属性集合
        Nested attrsAggNested = (Nested) stringAggregationMap.get("attrsAgg");
        Aggregations attrsAgg = attrsAggNested.getAggregations();
        Terms attrIdAgg = attrsAgg.get("attrIdAgg");
        List<SearchResponseAttrVo> searchAttrVoList = attrIdAgg.getBuckets().stream().map((attr) -> {
            SearchResponseAttrVo searchResponseAttrVo = new SearchResponseAttrVo();

            //一个属性的Id
            String attrId = attr.getKeyAsString();
            searchResponseAttrVo.setAttrId(Long.valueOf(attrId));

            //一个属性名
            Terms attrNameAggTerms = attr.getAggregations().get("attrNameAgg");
            String attrNameAgg = attrNameAggTerms.getBuckets().get(0).getKeyAsString();
            searchResponseAttrVo.setAttrName(attrNameAgg);

            //多个平台属性值
            Terms attrValueAggTerms = attr.getAggregations().get("attrValueAgg");
            List<String> attrValueList = attrValueAggTerms.getBuckets().
                    stream().map(Terms.Bucket::getKeyAsString).
                    collect(Collectors.toList());
            searchResponseAttrVo.setAttrValueList(attrValueList);

            return searchResponseAttrVo;
        }).collect(Collectors.toList());

        vo.setAttrsList(searchAttrVoList);
        return vo;
    }

    //商品下架
    @Override
    public void cancelSale(Long skuId) {
        goodsDao.deleteById(skuId);
    }
}
